<script setup lang="ts" name="SystemTenantPackageForm">
import { storeToRefs } from 'pinia'
import { useAppStoreWithOut } from '@/store/modules/app'
import { getIntDictOptions } from '@/utils/dict'
import { DICT_TYPE } from '@/enums/dictEnums'
import { TenantPackageApi, TenantPackageType } from '@/api/system/tenantPackage'
import { CommonStatusEnum } from '@/enums/commonEnums'
import { MenuApi } from '@/api/system/menu'
import { handleTree } from '@/utils/tree'
import { SystemMenuTypeEnum, SystemTenantPackageTypeEnum } from '@/enums/systemEnums'
import { filterPermitButtonFromMenu, computedMinWidth, recursionSetCheckboxStatus, setCheckboxStatus, MenuTreeType } from './helper'
const appStore = useAppStoreWithOut()
const { systemConfig } = storeToRefs(appStore)

const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗

const visible = ref(false) // 弹窗的是否展示
const title = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中：1）修改时的数据加载；2）提交的按钮禁用
const formType = ref('') // 表单的类型：create - 新增；update - 修改
const formData = ref({
  id: undefined as number | undefined,
  name: '',
  type: SystemTenantPackageTypeEnum.SYSTEM,
  accountCount: 2,
  menuIds: [],
  status: CommonStatusEnum.ENABLE,
  remark: ''
})
const formRules = reactive({
  name: [{ required: true, message: t('sys.post.rules', 'name'), trigger: 'blur' }],
  code: [{ required: true, message: t('sys.post.rules', 'code'), trigger: 'blur' }]
})
const formRef = ref() // 表单 Ref
const menuOptions = ref<MenuTreeType[]>([]) // 菜单树形结构
const menuExpand = ref(true) // 展开/折叠
const treeTableRef = ref() // 菜单树组件 Ref
const checkedAll = ref(false) // 全选/全不选
const isIndeterminate = ref(false) // 是否处于半选状态
const minWidth = ref(0) // 菜单权限列的最小宽度
const checkedParentIdList = ref<number[]>([]) // 选中权限按钮的父级菜单（用于处理选中状态及半选状态）
const checkedPermitList = ref<number[]>([]) // 选中的权限按钮 id
const refreshTable = ref(true) // 重新渲染表格状态

/** 打开弹窗 */
const open = async (type: string, id?: number) => {
  visible.value = true
  title.value = t('action', type)
  formType.value = type
  resetForm()
  // 修改时，设置数据
  if (id) {
    formLoading.value = true
    try {
      formData.value = await TenantPackageApi.detail(id)
    } finally {
      formLoading.value = false
    }
  }
  const menuList = await MenuApi.all()
  // 将按钮层数据特殊处理为菜单层数据的 buttonList
  const menuArr = filterPermitButtonFromMenu(menuList)
  // 计算按钮层文本连接后最长的，获取表格按钮列的最大宽度，同时获取已选中按钮层的父级数据
  const res = computedMinWidth(menuArr, formData.value.menuIds)
  // 将菜单数据转化为树形结构
  menuOptions.value = handleTree(menuArr)
  checkedParentIdList.value = res.checkedParentIdList
  minWidth.value = res.minWidth
  // 逆向递归处理父级的选中状态
  checkedParentIdList.value.forEach(item => {
    recursionSetCheckboxStatus(menuOptions.value, item)
  })
  // 处理全选按钮的选中状态
  const status = setCheckboxStatus(menuOptions.value)
  checkedAll.value = status.checkedAll
  isIndeterminate.value = status.isIndeterminate
}
defineExpose({ open }) // 提供 open 方法，用于打开弹窗

/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件，用于操作成功后的回调

// 提交表单前，将所有选中权限 id 提取出来
const getAllCheckedPermit = (data: MenuTreeType[]) => {
  data.forEach(item => {
    if (item.checkedList && item.checkedList.length > 0) {
      checkedPermitList.value.push(...item.checkedList)
    }
    if (item.children && item.children.length > 0) {
      getAllCheckedPermit(item.children)
    }
  })
}

const submitForm = async () => {
  // 校验表单
  if (!formRef) return
  const valid = await formRef.value.validate()
  if (!valid) return
  // 提交请求
  formLoading.value = true
  try {
    // 获取所有已选中的权限按钮 id
    getAllCheckedPermit(menuOptions.value)
    const data = formData.value as TenantPackageType
    data.menuIds = checkedPermitList.value
    if (formType.value === 'create') {
      await TenantPackageApi.create(data)
      message.success(t('message', 'createSuccess'))
    } else {
      await TenantPackageApi.update(data)
      message.success(t('message', 'updateSuccess'))
    }
    visible.value = false
    // 发送操作成功的事件
    emit('success')
  } finally {
    formLoading.value = false
  }
}

/** 重置表单 */
const resetForm = () => {
  // 重置选项
  checkedAll.value = false
  isIndeterminate.value = false
  menuExpand.value = true
  minWidth.value = 0
  checkedParentIdList.value = []
  checkedPermitList.value = []
  // 重置表单
  formData.value = {
    id: undefined,
    name: '',
    type: SystemTenantPackageTypeEnum.SYSTEM,
    accountCount: 0,
    menuIds: [],
    status: CommonStatusEnum.ENABLE,
    remark: ''
  }
  formRef.value?.resetFields()
}

/**
 *
 * @param value 权限按钮选中值
 * @param row 权限按钮的父级菜单
 */
const buttonCheckedChange = (_value, row: MenuTreeType) => {
  if (row.checkedList!.length === 0) {
    row.isIndeterminate = false
    row.checkedAll = false
  } else if (row.checkedList!.length === row.buttonList!.length) {
    row.isIndeterminate = false
    row.checkedAll = true
  } else {
    row.isIndeterminate = true
    row.checkedAll = false
  }
  checkboxChangeHandle(row.parentId)
}

// 设置checkbox的选中状态样式
const checkboxChangeHandle = parentId => {
  recursionSetCheckboxStatus(menuOptions.value, parentId)
  // 处理全选按钮的选中状态
  const status = setCheckboxStatus(menuOptions.value)
  checkedAll.value = status.checkedAll
  isIndeterminate.value = status.isIndeterminate
}

/** 表格全选/全不选 */
const handleCheckedAll = v => {
  checkedAll.value = v
  isIndeterminate.value = false
  checkedChangeHandle(menuOptions.value, checkedAll.value, isIndeterminate.value)
}

// 行全选|全不选
const rowCheckedChange = (v, row: MenuTreeType) => {
  row.checkedAll = v
  row.isIndeterminate = false
  if (row.type === SystemMenuTypeEnum.MENU) {
    if (v) {
      if (row.buttonList && row.buttonList.length > 0) {
        row.buttonList.forEach(item => {
          if (row.checkedList!.length > 0) {
            const index = row.checkedList!.findIndex(k => k === item.id)
            if (index === -1) {
              row.checkedList!.push(item.id!)
            }
          } else {
            row.checkedList!.push(item.id!)
          }
        })
      }
    } else {
      row.checkedList = []
    }
  }
  if (row.children && row.children.length > 0) {
    checkedChangeHandle(row.children, row.checkedAll, row.isIndeterminate)
  }
  checkboxChangeHandle(row.parentId)
}

// 设置按钮权限的选中值
const checkedChangeHandle = (data: MenuTreeType[], checkedAll, isIndeterminate) => {
  data.forEach(item => {
    item.checkedAll = checkedAll
    item.isIndeterminate = isIndeterminate
    if (item.children && item.children.length > 0) {
      checkedChangeHandle(item.children, checkedAll, isIndeterminate)
    }
    if (item.type === SystemMenuTypeEnum.MENU) {
      if (item.checkedAll) {
        if (item.buttonList && item.buttonList.length > 0) {
          item.buttonList.forEach(v => {
            if (item.checkedList!.length > 0) {
              const index = item.checkedList!.findIndex(k => k === v.id)
              if (index === -1) {
                item.checkedList!.push(v.id!)
              }
            } else {
              item.checkedList!.push(v.id!)
            }
          })
        }
      } else {
        item.checkedList = []
      }
    }
  })
}

/** 展开/折叠全部 */
const handleCheckedTreeExpand = () => {
  refreshTable.value = false
  nextTick(() => {
    refreshTable.value = true
  })
}
</script>

<template>
  <Dialog v-model="visible" :title="title" width="1024px">
    <el-form ref="formRef" v-loading="formLoading && systemConfig.loadingType === 'module'" :model="formData" :rules="formRules" label-width="80px">
      <el-form-item :label="t('sys.tenant.package', 'name')" prop="name">
        <el-input v-model="formData.name" clearable :placeholder="t('sys.post.rules', 'name')" />
      </el-form-item>
      <el-form-item :label="t('sys.tenant.package', 'type')" prop="type">
        <el-radio-group v-model="formData.type" class="radio-button">
          <el-radio-button v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_TENANT_PACKAGE_TYPE)" :key="dict.value" :value="dict.value">
            {{ dict.label }}
          </el-radio-button>
        </el-radio-group>
      </el-form-item>
      <ElFormItem :label="t('sys.tenant.package', 'accountCount')">
        <el-input-number v-model="formData.accountCount" :min="2" />
      </ElFormItem>
      <el-form-item :label="t('common', 'status')" prop="status">
        <el-radio-group v-model="formData.status" class="radio-button">
          <el-radio-button v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" :key="dict.value" :value="dict.value">
            {{ dict.label }}
          </el-radio-button>
        </el-radio-group>
      </el-form-item>
      <el-form-item :label="t('sys.role', 'menu')">
        <el-card class="w-full h-400px m-6px" shadow="never">
          <template #header>
            {{ t('sys.role', 'fold') }}
            <el-switch v-model="menuExpand" class="mr-24px" :active-text="t('action', 'unfold')" :inactive-text="t('action', 'fold')" inline-prompt @change="handleCheckedTreeExpand" />
          </template>
          <div class="abs-table">
            <el-table v-if="refreshTable" ref="treeTableRef" :data="menuOptions" border :default-expand-all="menuExpand" row-key="id">
              <el-table-column type="other" width="44" fixed="left">
                <template #header>
                  <el-checkbox v-model="checkedAll" :indeterminate="isIndeterminate" @change="handleCheckedAll" />
                </template>
                <template #default="scope">
                  <el-checkbox :key="scope.row.id" v-model="scope.row.checkedAll" :indeterminate="scope.row.isIndeterminate" @change="(v) => rowCheckedChange(v, scope.row)" />
                </template>
              </el-table-column>
              <el-table-column prop="title" :label="t('sys.role', 'menuName')" width="280" fixed="left">
                <template #default="scope">
                  {{ scope.row.title }}
                </template>
              </el-table-column>
              <!-- 可以设置最小宽度，让权限按钮不换行 :min-width="minWidth" -->
              <el-table-column prop="buttonList" :label="t('sys.role', 'permitName')">
                <template #default="scope">
                  <el-checkbox-group v-model="scope.row.checkedList">
                    <el-checkbox v-for="item in scope.row.buttonList" :key="item.id" :value="item.id" @change="(v) => buttonCheckedChange(v, scope.row)">{{ item.title }}</el-checkbox>
                  </el-checkbox-group>
                </template>
              </el-table-column>
            </el-table>
          </div>
        </el-card>
      </el-form-item>
      <el-form-item :label="t('common', 'remark')" prop="remark">
        <el-input v-model="formData.remark" clearable :placeholder="t('common.rules', 'remark')" type="textarea" />
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="visible = false">{{ t('action', 'cancel') }}</el-button>
      <el-button :disabled="formLoading" type="primary" @click="submitForm">{{ t('action', 'confirm') }}</el-button>
    </template>
  </Dialog>
</template>

<style scoped lang="scss">
.el-form{
  margin-right: -6px;
}

.el-card{
  display: flex;
  flex-direction: column;

  :deep(.el-card__header){
    padding: 12px var(--el-space);
    line-height: 0;
  }

  :deep(.el-card__body) {
    position: relative;
    display: flex;
    flex: 1;
  }
}

.abs-table {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;

  .el-table {
    width: 100%;
    height: 100%;
  }
}

.el-table--border {
  &::before,&::after{
    display: none;
  }

  :deep(.el-table__cell) {
    &:last-child{
      border-right: none;
    }
  }

  :deep(.el-table__row) {
    &:last-child{
      td.el-table__cell{
        border-bottom: none;
      }
    }
  }

  :deep(.el-table__inner-wrapper) {
    &::before,&::after{
      display: none;
    }

  }
}

:deep(.el-table__border-bottom-patch), :deep(.el-table__border-left-patch){
  display: none;
}
</style>
